/* uart-i.c
 *
 * Non-interrupt driven UART driver for AtTiny2313V
 *
 * John Boiles
 * 3 Nov 2008
 * Based on HC12 code by Jonathon W Valvano
 */

#define CR   0x0D
#define LF   0x0A
#define BS   0x08
#define ESC  0x1B
#define SPC  0x20       
#define DEL  0x7F

#define OUTSTRING 0
#define INUDEC 0

/* Initialize UART */
void UART_Init (unsigned long baudrate) { 
  /* Set the baud rate */   
  //Assumes 8Mhz clock in single speed (U2X=0) mode
  switch(baudrate){
  case 9600:   UBRRL = 51; break; //.2% error
  case 19200:  UBRRL = 25; break; //.2% error
  case 38400:  UBRRL = 12; break; //.2% error
  case 57600:  UBRRL = 8; break;  //-3.5% error
  case 115200: UBRRL = 1; break;  //8.5% error
  default: UBRRL=12;
  }

  /* Enable UART receiver and transmitter */   
  UCSRB = (1 << RXEN) | (1 << TXEN) | (1<<RXCIE);   
  /* set to 8 data bits, 1 stop bit */   
  UCSRC = (1<<UCSZ1) | (1<<UCSZ0); } 


volatile unsigned char RxData[3];
extern volatile short reference;
ISR (USART_RX_vect){
  RxData[0] = UDR;
  //Check to make sure we are syncd
  if((RxData[0]=='+')||(RxData[0]=='-')){
    while (!(UCSRA & (1 << RXC))); 
    RxData[1] = UDR;
    while (!(UCSRA & (1 << RXC)));   
    RxData[2] = UDR;
  
    reference = (RxData[1] << 8) + (RxData[2]);
    if(RxData[0]=='-'){
      reference = -reference;
    }
  }
}

/* Read and write functions */ 
unsigned char UART_InChar (void) {   
  /* Wait for incomming data */   
  while (!(UCSRA & (1 << RXC)));   
  /* Return the data */   
  return UDR; 
} 


unsigned char UART_InChar2 (void) {
  if(!(UCSRA & (1 << RXC))){return 0;}
  return UDR;
}


void UART_OutChar (unsigned char data) {   
  /* Wait for empty transmit buffer */   
  while (!(UCSRA & (1 << UDRE)));   
  /* Start transmittion */   
  UDR = data; 
}

#if(OUTSTRING)
//-------------------------UART_OutString------------------------
// Output String (NULL termination), interrupt synchronization
// Input: pointer to a NULL-terminated string to be transferred
// Output: none
void UART_OutString(char *pt){
  while(*pt){
    UART_OutChar(*pt);
    pt++;
  }
}
#endif

#if(INUDEC)
//----------------------UART_InUDec-------------------------------
// InUDec accepts ASCII input in unsigned decimal format
//     and converts to a 16 bit unsigned number
//     valid range is 0 to 65535
// Input: none
// Output: 16-bit unsigned number
// If you enter a number above 65535, it will truncate without an error
// Backspace will remove last digit typed
unsigned short UART_InUDec(void){	
unsigned short number=0, length=0;
char character;
  character = UART_InChar();	
  while(character!=CR){ // accepts until carriage return input
// The next line checks that the input is a digit, 0-9.
// If the character is not 0-9, it is ignored and not echoed
    if((character>='0') && (character<='9')) {
      number = 10*number+(character-'0');   // this line overflows if above 65535
      length++;
      UART_OutChar(character);
    } 
// If the input is a backspace, then the return number is
// changed and a backspace is outputted to the screen
    else if((character==BS) && length){
      number /= 10;
      length--;
      UART_OutChar(character);
    }
    character = UART_InChar();	
  }
  return number;
}
#endif


//-----------------------UART_OutUDec-----------------------
// Output a 16-bit number in unsigned decimal format
// Input: 16-bit number to be transferred
// Output: none
// Variable format 1-5 digits with no space before or after
/*
void UART_OutUDec(unsigned short n){
// This function uses recursion to convert decimal number
//   of unspecified length as an ASCII string 
  if(n >= 10){
    UART_OutUDec(n/10);
    n = n%10;
  }
  UART_OutChar(n+'0'); // n is between 0 and 9 
}


void UART_OutDec32(int32_t input){
  if(input < 0){
    input = -input;
    UART_OutChar('-');
  }
  UART_OutUDec(input >> 16);
  UART_OutUDec((int16_t)input);
}
*/
/*
void UART_OutDec16(int16_t input){
  if(input < 0){
    input = -input;
    UART_OutChar('-');
  }
  UART_OutUDec(input);
}
*/

//---------------------UART_InUHex----------------------------------------
// Accepts ASCII input in unsigned hexadecimal (base 16) format
// Input: none
// Output: 16-bit unsigned number
// No '$' or '0x' need be entered, just the 1 to 4 hex digits
// It will convert lower case a-f to uppercase A-F
//     and converts to a 16 bit unsigned number
//     value range is 0 to FFFF
// If you enter a number above FFFF, it will truncate without an error
// Backspace will remove last digit typed
/*
unsigned short UART_InUHex(void){	
unsigned short number=0, digit, length=0;
char character;
  character = UART_InChar();
  while(character!=CR){	
    digit = 0x10; // assume bad
    if((character>='0') && (character<='9')){
      digit = character-'0';
    }
    else if((character>='A') && (character<='F')){ 
      digit = (character-'A')+0xA;
    }
    else if((character>='a') && (character<='f')){ 
      digit = (character-'a')+0xA;
    }
// If the character is not 0-9 or A-F, it is ignored and not echoed
    if(digit<=0xF ){	
      number = number*0x10+digit;
      length++;
      UART_OutChar(character);
    }
// Backspace outputted and return value changed if a backspace is inputted
    else if(character==BS && length){
      number /=0x10;
      length--;
      UART_OutChar(character);
    }
    character = UART_InChar();
  }
  return number;
}
*/
//--------------------------UART_OutUHex----------------------------
// Output a 16 bit number in unsigned hexadecimal format
// Input: 16-bit number to be transferred
// Output: none
// Variable format 1 to 4 digits with no space before or after
/*
void UART_OutUHex(unsigned short number){
// This function uses recursion to convert the number of 
//   unspecified length as an ASCII string
  if(number>=0x10)	{
    UART_OutUHex(number/0x10);
    UART_OutUHex(number%0x10);
  }
  else if(number<0xA){
    UART_OutChar(number+'0');
  }
  else{
    UART_OutChar((number-0x0A)+'A');
  }
}
*/
//------------------------UART_InString------------------------
// This function accepts ASCII characters from the serial port
//    and adds them to a string until a carriage return is inputted 
//    or until max length of the string is reached.  
// It echoes each character as it is inputted.  
// If a backspace is inputted, the string is modified 
//    and the backspace is echoed
// InString terminates the string with a null character
// -- Modified by Agustinus Darmawan + Mingjie Qiu --
/*
void UART_InString(char *string, unsigned short max) {	
int length=0;
char character;
  character = UART_InChar();
  while(character!=CR){
    if(character==BS){
      if(length){
        string--;
        length--;
        UART_OutChar(BS);
      }
    }
    else if(length<max){
      *string++=character;
      length++; 
      UART_OutChar(character);
    }
    character = UART_InChar();
  }
  *string = 0;
}
*/
